package com.keqiang.filepicker

import android.annotation.SuppressLint
import android.app.Dialog
import android.content.Intent
import android.content.res.Configuration
import android.graphics.Color
import android.graphics.drawable.ColorDrawable
import android.net.Uri
import android.os.Build
import android.os.Bundle
import android.os.Environment
import android.os.Parcelable
import android.provider.MediaStore
import android.view.Gravity
import android.view.View
import android.view.ViewGroup
import android.view.Window
import android.view.inputmethod.EditorInfo
import android.widget.*
import androidx.annotation.RequiresApi
import androidx.appcompat.app.AppCompatActivity
import androidx.appcompat.widget.AppCompatImageView
import androidx.core.content.ContextCompat
import androidx.core.content.FileProvider
import androidx.core.view.GravityCompat
import androidx.core.view.ViewCompat
import androidx.core.view.WindowCompat
import androidx.core.view.WindowInsetsCompat
import androidx.core.widget.addTextChangedListener
import androidx.drawerlayout.widget.DrawerLayout
import androidx.recyclerview.widget.GridLayoutManager
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.hjq.permissions.OnPermissionCallback
import com.hjq.permissions.Permission
import com.hjq.permissions.XXPermissions
import com.keqiang.breadcrumb.Breadcrumb
import com.keqiang.breadcrumb.Folder
import com.keqiang.filepicker.utils.MimeUtils
import com.keqiang.filepicker.utils.ThreadUtils
import kotlinx.coroutines.Job
import kotlinx.coroutines.delay
import java.io.File
import java.util.*


/**
 * 文件选择主界面
 *
 * @author Created by wanggaowan on 2022/5/18 14:00
 */
class FilePickerActivity : AppCompatActivity() {

    private lateinit var mIvMenu: ImageView
    private lateinit var mIvBack: ImageView
    private lateinit var mTvTitle: TextView
    private lateinit var mIvMore: ImageView
    private lateinit var mIvSearch: ImageView
    private lateinit var mBreadcrumb: Breadcrumb
    private lateinit var mRecyclerView: RecyclerView
    private lateinit var mLlImage: LinearLayout
    private lateinit var mLlVideo: LinearLayout
    private lateinit var mLlAudio: LinearLayout
    private lateinit var mLlDocument: LinearLayout
    private lateinit var mLlDownload: LinearLayout
    private lateinit var mLlSdcard: LinearLayout
    private lateinit var mLlLately: LinearLayout
    private lateinit var mLlZip: LinearLayout
    private lateinit var mDrawerLayout: DrawerLayout
    private lateinit var mEtSearch: EditText
    private lateinit var mIvChangeLayout: ImageView

    private lateinit var mAdapter: FileAdapter
    private lateinit var mLayoutManager: LinearLayoutManager

    private var mTaskJob: Job? = null

    private val mChosenFileList = mutableListOf<File>()
    private var maxChosenCount = 1

    // 允许选择的文件的扩展名
    private var mFileExtensionList: Array<String>? = null

    // 允许选择的文件的MIME
    private var mFileMimeList: Array<String>? = null

    // 排除的文件的扩展名
    private var mExcludeFileExtensionList: Array<String>? = null

    // 排除的的文件的MIME
    private var mExcludeFileMimeList: Array<String>? = null

    // 允许选择的文件的MIME SQL查询条件语句
    private var mFileMimeWhereSql: String? = null

    // 排除的文件的MIME SQL查询条件语句
    private var mExcludeFileMimeWhereSql: String? = null

    // 是否显示隐藏文件
    private var mShowHideFile = false

    private lateinit var mProviderAuthorities: String

    private var maxFileSize: Long = -1L

    private var mShowMenu = true

    // 排序类型
    private var mSortType: Int? = null
        get() {
            if (field != null) {
                return field
            }

            val folder = mBreadcrumb.currentFolder
            if (folder != null && (folder.id == LATELY_PATH || folder.id == IMAGE_PATH)) {
                return SORT_TYPE_TIME_DESC
            }

            return SORT_TYPE_NAME_AZ
        }

    /**
     * 当前展示内容根路径
     */
    private var mRootPath =
        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) SDCARD_PATH else LATELY_PATH

    private var mSearchMode = false
    private var mSearchText: String? = null

    // 记录搜索之前当前文件夹下的所有内容
    private var mCurrentFolderFiles: List<File>? = null

    // android 10以后搜索模式开启之前的全路径
    private var mSearchPreAllFolder: List<Folder>? = null

    // 是否拥有磁盘访问权限
    private var mHavePermission = false

    // 当前是否是暗黑模式
    private var mDarkTheme: Boolean = false

    // 当前是否是网格布局
    private var mGridLayout: Boolean? = null

    // 如果设置网格布局，默认为两列
    private var mSpanCount: Int = 2

    private var mClickFileChosen = false

    override fun onCreate(savedInstanceState: Bundle?) {
        WindowCompat.getInsetsController(window, window.decorView)?.let {
            // 设置导航栏字体为黑色
            it.isAppearanceLightStatusBars = true
        }

        super.onCreate(savedInstanceState)
        setContentView(R.layout.fp_activity_file_pciker)
        mDarkTheme =
            resources.configuration.uiMode and Configuration.UI_MODE_NIGHT_MASK == Configuration.UI_MODE_NIGHT_YES
        initView()
        initData()
        initEvent()
    }

    fun initView() {
        mIvMenu = findViewById(R.id.iv_menu)
        mIvBack = findViewById(R.id.iv_back)
        mTvTitle = findViewById(R.id.tv_title)
        mIvMore = findViewById(R.id.iv_more)
        mIvSearch = findViewById(R.id.iv_search)
        mBreadcrumb = findViewById(R.id.breadcrumb)
        mRecyclerView = findViewById(R.id.recyclerView)
        mLlImage = findViewById(R.id.ll_image)
        mLlVideo = findViewById(R.id.ll_video)
        mLlAudio = findViewById(R.id.ll_audio)
        mLlDocument = findViewById(R.id.ll_document)
        mLlDownload = findViewById(R.id.ll_download)
        mLlSdcard = findViewById(R.id.ll_sdcard)
        mLlLately = findViewById(R.id.ll_lately)
        mLlZip = findViewById(R.id.ll_zip)
        mDrawerLayout = findViewById(R.id.drawerLayout)
        mEtSearch = findViewById(R.id.et_search)
        mIvChangeLayout = findViewById(R.id.iv_change_layout)

        mEtSearch.hint = FilePicker.stringRes.search
        findViewById<TextView>(R.id.tv_open_document).text = FilePicker.stringRes.openDocument
        findViewById<TextView>(R.id.tv_lately).text = FilePicker.stringRes.lately
        findViewById<TextView>(R.id.tv_image).text = FilePicker.stringRes.image
        findViewById<TextView>(R.id.tv_video).text = FilePicker.stringRes.video
        findViewById<TextView>(R.id.tv_audio).text = FilePicker.stringRes.audio
        findViewById<TextView>(R.id.tv_document).text = FilePicker.stringRes.document
        findViewById<TextView>(R.id.tv_zip).text = FilePicker.stringRes.zip
        findViewById<TextView>(R.id.tv_download).text = FilePicker.stringRes.download
        findViewById<TextView>(R.id.tv_root_folder).text = FilePicker.stringRes.rootFolder

        mBreadcrumb.setTextSize((resources.displayMetrics.scaledDensity * 16).toInt())
        mDrawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_CLOSED)
        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) {
            mLlLately.visibility = View.GONE
            mLlDocument.visibility = View.GONE
            mLlZip.visibility = View.GONE
            mLlDownload.visibility = View.GONE
        }
    }

    @SuppressLint("InflateParams")
    fun initData() {
        mProviderAuthorities = "${applicationInfo.packageName}.FPFileProvider"
        mShowMenu = intent.getBooleanExtra(SHOW_MENU, true)
        if (!mShowMenu) {
            mIvMenu.visibility = View.GONE
        }

        mSpanCount = intent.getIntExtra(SPAN_COUNT, 2)
        val layout = intent.getStringExtra(PREFERRED_LAYOUT)
        if (layout == PreferredLayout.GRID) {
            mGridLayout = true
        } else if (layout == PreferredLayout.LINEAR) {
            mGridLayout = false
        }
        setNewAdapter()

        XXPermissions.with(this)
            .permission(Permission.MANAGE_EXTERNAL_STORAGE)
            .request(object : OnPermissionCallback {
                override fun onGranted(permissions: MutableList<String>?, all: Boolean) {
                    mHavePermission = true
                    intent.getStringExtra(DEFAULT_OPEN_PATH)?.let { mRootPath = it }
                    mFileMimeList = intent.getStringArrayExtra(CHOSEN_FILE_MIME)
                    mExcludeFileMimeList = intent.getStringArrayExtra(EXCLUDE_FILE_MIME)
                    mFileExtensionList = intent.getStringArrayExtra(CHOSEN_FILE_EXTENSION)
                    mExcludeFileExtensionList = intent.getStringArrayExtra(EXCLUDE_FILE_EXTENSION)
                    maxChosenCount = intent.getIntExtra(MAX_CHOOSE_COUNT, 1)
                    maxFileSize = intent.getLongExtra(MAX_FILE_SIZE, -1L)
                    if (!mFileMimeList.isNullOrEmpty()) {
                        mFileMimeWhereSql = listToWhereSql(mFileMimeList!!)
                    }
                    if (!mExcludeFileMimeList.isNullOrEmpty()) {
                        mExcludeFileMimeWhereSql = listToWhereSql(mExcludeFileMimeList!!)
                    }

                    mIvMore.visibility = View.VISIBLE
                    mIvSearch.visibility = View.VISIBLE
                    mBreadcrumb.visibility = View.VISIBLE
                    updateAdapterLayout(isGridLayout())
                    mLayoutManager = mRecyclerView.layoutManager as LinearLayoutManager

                    initFunctionEvent()
                    resetFolder(mRootPath)
                }

                @SuppressLint("NotifyDataSetChanged")
                override fun onDenied(permissions: MutableList<String>?, never: Boolean) {
                    super.onDenied(permissions, never)
                    mHavePermission = false
                    intent.getStringExtra(DEFAULT_OPEN_PATH)?.let { mRootPath = it }
                    resetFolder(mRootPath)

                    mAdapter.notifyDataSetChanged()
                }
            })
    }

    private fun isGridLayout(): Boolean {
        if (mGridLayout != null) {
            return mGridLayout!!
        }

        if (mRootPath == IMAGE_PATH || mRootPath == VIDEO_PATH) {
            return true
        }

        if (mRootPath == SEARCH_PATH) {
            mSearchPreAllFolder?.let {
                if (it.isNotEmpty()) {
                    val path = it[0].id
                    if (path == IMAGE_PATH || path == VIDEO_PATH) {
                        return true
                    }
                }
            }
        }

        return false
    }

    /**
     * 将列表转化为sql查询条件语句
     */
    private fun listToWhereSql(params: Array<String>): String {
        val builder = StringBuilder()
        for (index in params.indices) {
            val str = params[index]
            if (index == 0) {
                builder.append("'$str'")
            } else {
                builder.append(",'$str'")
            }
        }
        return builder.toString()
    }

    fun initEvent() {
        mIvMenu.setOnClickListener {
            mDrawerLayout.openDrawer(GravityCompat.START)
            mBreadcrumb.firstFolder?.let {
                when (it.id) {
                    SDCARD_PATH -> {
                        setMenuSelected(mLlLately, false)
                        setMenuSelected(mLlImage, false)
                        setMenuSelected(mLlVideo, false)
                        setMenuSelected(mLlAudio, false)
                        setMenuSelected(mLlDocument, false)
                        setMenuSelected(mLlZip, false)
                        setMenuSelected(mLlDownload, false)
                        setMenuSelected(mLlSdcard, true)
                    }

                    IMAGE_PATH -> {
                        setMenuSelected(mLlLately, false)
                        setMenuSelected(mLlImage, true)
                        setMenuSelected(mLlVideo, false)
                        setMenuSelected(mLlAudio, false)
                        setMenuSelected(mLlDocument, false)
                        setMenuSelected(mLlZip, false)
                        setMenuSelected(mLlDownload, false)
                        setMenuSelected(mLlSdcard, false)
                    }

                    VIDEO_PATH -> {
                        setMenuSelected(mLlLately, false)
                        setMenuSelected(mLlImage, false)
                        setMenuSelected(mLlVideo, true)
                        setMenuSelected(mLlAudio, false)
                        setMenuSelected(mLlDocument, false)
                        setMenuSelected(mLlZip, false)
                        setMenuSelected(mLlDownload, false)
                        setMenuSelected(mLlSdcard, false)
                    }

                    AUDIO_PATH -> {
                        setMenuSelected(mLlLately, false)
                        setMenuSelected(mLlImage, false)
                        setMenuSelected(mLlVideo, false)
                        setMenuSelected(mLlAudio, true)
                        setMenuSelected(mLlDocument, false)
                        setMenuSelected(mLlZip, false)
                        setMenuSelected(mLlDownload, false)
                        setMenuSelected(mLlSdcard, false)
                    }

                    DOWNLOAD_PATH -> {
                        setMenuSelected(mLlLately, false)
                        setMenuSelected(mLlImage, false)
                        setMenuSelected(mLlVideo, false)
                        setMenuSelected(mLlAudio, false)
                        setMenuSelected(mLlDocument, false)
                        setMenuSelected(mLlZip, false)
                        setMenuSelected(mLlDownload, true)
                        setMenuSelected(mLlSdcard, false)
                    }

                    DOCUMENT_PATH -> {
                        setMenuSelected(mLlLately, false)
                        setMenuSelected(mLlImage, false)
                        setMenuSelected(mLlVideo, false)
                        setMenuSelected(mLlAudio, false)
                        setMenuSelected(mLlDocument, true)
                        setMenuSelected(mLlZip, false)
                        setMenuSelected(mLlDownload, false)
                        setMenuSelected(mLlSdcard, false)
                    }

                    LATELY_PATH -> {
                        setMenuSelected(mLlLately, true)
                        setMenuSelected(mLlImage, false)
                        setMenuSelected(mLlVideo, false)
                        setMenuSelected(mLlAudio, false)
                        setMenuSelected(mLlDocument, false)
                        setMenuSelected(mLlZip, false)
                        setMenuSelected(mLlDownload, false)
                        setMenuSelected(mLlSdcard, false)
                    }

                    ZIP_PATH -> {
                        setMenuSelected(mLlLately, false)
                        setMenuSelected(mLlImage, false)
                        setMenuSelected(mLlVideo, false)
                        setMenuSelected(mLlAudio, false)
                        setMenuSelected(mLlDocument, false)
                        setMenuSelected(mLlZip, true)
                        setMenuSelected(mLlDownload, false)
                        setMenuSelected(mLlSdcard, false)
                    }
                }
            }
        }

        mBreadcrumb.setFolderChangeListener { folder ->
            if (mHavePermission) {
                exitSearchMode()
                onFolderChange(folder)
            } else {
                updateTitle()
            }
        }

        mIvChangeLayout.setOnClickListener {
            mGridLayout = if (mGridLayout == null) {
                val isGridLayout = isGridLayout()
                !isGridLayout
            } else {
                !mGridLayout!!
            }
            updateAdapterLayout(mGridLayout!!)
        }

        mLlImage.setOnClickListener {
            mDrawerLayout.closeDrawer(GravityCompat.START)
            mBreadcrumb.currentFolder?.let {
                if (it.id == IMAGE_PATH) {
                    return@setOnClickListener
                }
            }

            resetFolder(IMAGE_PATH)
            if (mGridLayout == null) {
                updateAdapterLayout(isGridLayout())
            }
        }

        mLlVideo.setOnClickListener {
            mDrawerLayout.closeDrawer(GravityCompat.START)
            mBreadcrumb.currentFolder?.let {
                if (it.id == VIDEO_PATH) {
                    return@setOnClickListener
                }
            }
            resetFolder(VIDEO_PATH)
            if (mGridLayout == null) {
                updateAdapterLayout(isGridLayout())
            }
        }

        mLlAudio.setOnClickListener {
            mDrawerLayout.closeDrawer(GravityCompat.START)
            mBreadcrumb.currentFolder?.let {
                if (it.id == AUDIO_PATH) {
                    return@setOnClickListener
                }
            }
            resetFolder(AUDIO_PATH)
            if (mGridLayout == null) {
                updateAdapterLayout(isGridLayout())
            }
        }

        mLlDocument.setOnClickListener {
            mDrawerLayout.closeDrawer(GravityCompat.START)
            mBreadcrumb.currentFolder?.let {
                if (it.id == DOCUMENT_PATH) {
                    return@setOnClickListener
                }
            }
            resetFolder(DOCUMENT_PATH)
            if (mGridLayout == null) {
                updateAdapterLayout(isGridLayout())
            }
        }

        mLlDownload.setOnClickListener {
            mDrawerLayout.closeDrawer(GravityCompat.START)
            mBreadcrumb.currentFolder?.let {
                if (it.id == DOWNLOAD_PATH) {
                    return@setOnClickListener
                }
            }
            resetFolder(DOWNLOAD_PATH)
            if (mGridLayout == null) {
                updateAdapterLayout(isGridLayout())
            }
        }

        mLlSdcard.setOnClickListener {
            mDrawerLayout.closeDrawer(GravityCompat.START)
            mBreadcrumb.currentFolder?.let {
                if (it.id == SDCARD_PATH) {
                    return@setOnClickListener
                }
            }
            resetFolder(SDCARD_PATH)
            if (mGridLayout == null) {
                updateAdapterLayout(isGridLayout())
            }
        }

        mLlLately.setOnClickListener {
            mDrawerLayout.closeDrawer(GravityCompat.START)
            mBreadcrumb.currentFolder?.let {
                if (it.id == LATELY_PATH) {
                    return@setOnClickListener
                }
            }
            resetFolder(LATELY_PATH)
            if (mGridLayout == null) {
                updateAdapterLayout(isGridLayout())
            }
        }

        mLlZip.setOnClickListener {
            mDrawerLayout.closeDrawer(GravityCompat.START)
            mBreadcrumb.currentFolder?.let {
                if (it.id == ZIP_PATH) {
                    return@setOnClickListener
                }
            }
            resetFolder(ZIP_PATH)
            if (mGridLayout == null) {
                updateAdapterLayout(isGridLayout())
            }
        }
    }

    /**
     * 设置菜单项选中/未选中样式
     */
    private fun setMenuSelected(parent: ViewGroup, selected: Boolean) {

        var normalIcon = 0
        var selectedIcon = 0
        when (parent.id) {
            R.id.ll_lately -> {
                normalIcon = R.drawable.fp_menu_lately_24
                selectedIcon = R.drawable.fp_menu_lately_blue
            }

            R.id.ll_image -> {
                normalIcon = R.drawable.fp_menu_image_24
                selectedIcon = R.drawable.fp_menu_image_blue_24
            }

            R.id.ll_video -> {
                normalIcon = R.drawable.fp_menu_movie_24
                selectedIcon = R.drawable.fp_menu_movie_blue
            }

            R.id.ll_audio -> {
                normalIcon = R.drawable.fp_menu_audio_24
                selectedIcon = R.drawable.fp_menu_audio_blue
            }

            R.id.ll_document -> {
                normalIcon = R.drawable.fp_menu_file_24
                selectedIcon = R.drawable.fp_menu_file_blue_24
            }

            R.id.ll_zip -> {
                normalIcon = R.drawable.fp_menu_zip
                selectedIcon = R.drawable.fp_menu_zip_blue
            }

            R.id.ll_download -> {
                normalIcon = R.drawable.fp_menu_download_24
                selectedIcon = R.drawable.fp_menu_download_blue
            }

            R.id.ll_sdcard -> {
                normalIcon = R.drawable.fp_menu_phone_24
                selectedIcon = R.drawable.fp_menu_phone_blue
            }
        }

        val linearLayout = parent.getChildAt(0) as LinearLayout
        if (selected) {
            linearLayout.setBackgroundColor(ContextCompat.getColor(this, R.color.fp_bg_color_tint_sky_blue))
            val child2 = linearLayout.getChildAt(1) as TextView
            child2.setTextColor(ContextCompat.getColor(this, R.color.fp_text_color_sky_blue))

            val child = linearLayout.getChildAt(0) as ImageView
            child.setImageResource(selectedIcon)
        } else {
            linearLayout.background = null
            val child2 = linearLayout.getChildAt(1) as TextView
            child2.setTextColor(ContextCompat.getColor(this, R.color.fp_text_color_333))

            val child = linearLayout.getChildAt(0) as ImageView
            child.setImageResource(normalIcon)
        }
    }

    /**
     * 退出搜索模式
     */
    private fun exitSearchMode() {
        if (!mSearchMode) {
            return
        }

        mAdapter.isUseEmpty = true
        mSearchMode = false
        mCurrentFolderFiles = null
        val rootFolderId = mBreadcrumb.firstFolder?.id
        if (rootFolderId == SEARCH_PATH) {
            mIvBack.visibility = View.VISIBLE
            mIvMenu.visibility = View.GONE
        } else {
            mIvBack.visibility = View.GONE
            mIvMenu.visibility = if (mShowMenu) View.VISIBLE else View.GONE
        }

        ViewCompat.getWindowInsetsController(mEtSearch)?.hide(WindowInsetsCompat.Type.ime())
        mIvMore.visibility = View.VISIBLE
        mIvSearch.visibility = View.VISIBLE
        mEtSearch.visibility = View.GONE
        mTvTitle.visibility = View.VISIBLE
        mEtSearch.text = null
        updateTitle()
    }

    private fun initFunctionEvent() {
        mIvBack.setOnClickListener { clickExitSearchMode() }

        mIvSearch.setOnClickListener {
            mSearchMode = true
            mIvBack.visibility = View.VISIBLE
            mIvMenu.visibility = View.GONE
            mIvMore.visibility = View.GONE
            mIvSearch.visibility = View.GONE
            mEtSearch.visibility = View.VISIBLE
            mTvTitle.visibility = View.GONE

            if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) {
                mBreadcrumb.currentFolder?.let {
                    val visiblePosition = mLayoutManager.findFirstVisibleItemPosition()
                    it.extraData = visiblePosition
                }
                mCurrentFolderFiles = ArrayList(mAdapter.data)
            } else {
                val rootFolderId = mBreadcrumb.firstFolder?.id
                if (rootFolderId != SEARCH_PATH) {
                    // 只记录搜索之前的目录结构
                    mBreadcrumb.currentFolder?.let {
                        val visiblePosition = mLayoutManager.findFirstVisibleItemPosition()
                        it.extraData = visiblePosition
                    }
                    mSearchPreAllFolder = mBreadcrumb.allFolder
                }

                resetFolder(SEARCH_PATH)
                mAdapter.isUseEmpty = false
                updateAdapterData(null)
                if (mGridLayout == null) {
                    updateAdapterLayout(isGridLayout())
                }
            }

            mEtSearch.requestFocus()
            mEtSearch.post {
                ViewCompat.getWindowInsetsController(mEtSearch)?.show(WindowInsetsCompat.Type.ime())
            }
        }

        mIvMore.setOnClickListener {
            if (mChosenFileList.size > 0) {
                val uris = mChosenFileList.map { fileToUri(it) }
                val intent = Intent()
                intent.putParcelableArrayListExtra(CHOSEN_DATA_LIST, ArrayList(uris))
                setResult(RESULT_OK, intent)
                finish()
                return@setOnClickListener
            }

            showMenu()
        }

        mEtSearch.addTextChangedListener {
            if (!mSearchMode) {
                return@addTextChangedListener
            }

            doSearch()
        }

        mEtSearch.setOnEditorActionListener { _, actionId, _ ->
            if (actionId == EditorInfo.IME_ACTION_SEARCH) {
                // mEtSearch.clearFocus()
                // ViewCompat.getWindowInsetsController(mEtSearch)?.hide(WindowInsetsCompat.Type.ime())
                doSearch()
                return@setOnEditorActionListener true
            }
            return@setOnEditorActionListener false
        }

        mBreadcrumb.setFolderChangeListener { folder ->
            exitSearchMode()
            onFolderChange(folder)
        }

        mAdapter.setOnItemClickListener { _, _, pos ->
            val data = mAdapter.data
            if (pos < 0 || pos >= data.size) {
                return@setOnItemClickListener
            }

            val file = data[pos]
            clickFile(file, pos)
        }
    }

    private fun doSearch() {
        val str = mEtSearch.text.toString().trim()
        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) {
            // 低版本仅搜索当前目录
            searchCurrentFolder(str)
            return
        }

        mSearchText = str
        searchFile(str, mSearchPreAllFolder?.first()?.id == SDCARD_PATH)
    }

    @SuppressLint("InflateParams")
    private fun setNewAdapter() {
        val position =
            if (this::mLayoutManager.isInitialized) mLayoutManager.findFirstVisibleItemPosition() else RecyclerView.NO_POSITION
        val isGridLayout = isGridLayout()
        mLayoutManager = if (isGridLayout) {
            GridLayoutManager(this, mSpanCount).apply {
                spanSizeLookup = object : GridLayoutManager.SpanSizeLookup() {
                    override fun getSpanSize(position: Int): Int {
                        val data = mAdapter.data
                        if (position < 0 || position >= data.size) {
                            return 1
                        }

                        val file = data[position]
                        return if (file.path == PLACE_HOLDER_FOlDER) {
                            mSpanCount - position % mSpanCount
                        } else {
                            1
                        }
                    }
                }
            }
        } else {
            LinearLayoutManager(this)
        }
        mRecyclerView.layoutManager = mLayoutManager

        val data: List<File>? = if (this::mAdapter.isInitialized) {
            mAdapter.data
        } else {
            null
        }

        mAdapter =
            FileAdapter(this@FilePickerActivity, mProviderAuthorities, isGridLayout, data)
        val emptyView = layoutInflater.inflate(R.layout.fp_empty_data, null)
        emptyView.findViewById<TextView>(R.id.tv_content).text = FilePicker.stringRes.emptyData
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
            emptyView.isForceDarkAllowed = false
        }
        mAdapter.setEmptyView(emptyView)
        mRecyclerView.adapter = mAdapter
        if (position != RecyclerView.NO_POSITION) {
            mLayoutManager.scrollToPositionWithOffset(position, 0)
        }

        if (mHavePermission) {
            mAdapter.setOnItemClickListener { _, _, pos ->
                val list = mAdapter.data
                if (pos < 0 || pos >= list.size) {
                    return@setOnItemClickListener
                }

                val file = list[pos]
                clickFile(file, pos)
            }
        }
    }

    /**
     * 点击列表中的文件或目录
     */
    private fun clickFile(file: File, position: Int) {
        if (file.isDirectory) {
            // 如果是搜索模式且为android10以下低版本，已在切换搜索模式时记录了当前点击文件夹所在目录的位置
            if (!mSearchMode) {
                mBreadcrumb.currentFolder?.let {
                    val visiblePosition = mLayoutManager.findFirstVisibleItemPosition()
                    it.extraData = visiblePosition
                }
            }

            exitSearchMode()
            mBreadcrumb.addFolderSpan(Folder(file.path, file.name))
            updateTitle()
            return
        }

        mClickFileChosen = true
        if (maxChosenCount == 1) {
            val uri = fileToUri(file)
            val intent = Intent()
            intent.putParcelableArrayListExtra(CHOSEN_DATA_LIST, arrayListOf<Parcelable>(uri))
            setResult(RESULT_OK, intent)
            finish()
            return
        }

        val index = isFileChosen(file)
        if (index == RecyclerView.NO_POSITION) {
            if (mChosenFileList.size >= maxChosenCount) {
                if (maxChosenCount <= 0) {
                    updateTitle()
                }
                return
            }

            mChosenFileList.add(file)
        } else {
            mChosenFileList.removeAt(index)
        }
        mAdapter.notifyItemChanged(position)
        updateTitle()
    }

    private fun fileToUri(file: File): Uri {
        return try {
            FileProvider.getUriForFile(this, mProviderAuthorities, file)
        } catch (e: Exception) {
            try {
                Uri.fromFile(file)
            } catch (e: Exception) {
                Uri.EMPTY
            }
        }
    }

    /**
     * 点击退出搜索模式，此时主动点击退出搜索模式
     */
    private fun clickExitSearchMode() {
        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) {
            var position = 0
            mBreadcrumb.currentFolder?.let {
                position = it.extraData as? Int ?: 0
                it.extraData = null
            }
            updateAdapterData(mCurrentFolderFiles, position)
            exitSearchMode()
        } else {
            mIvBack.visibility = View.GONE
            mIvMenu.visibility = View.VISIBLE
            if (!mSearchPreAllFolder.isNullOrEmpty()) {
                mBreadcrumb.reset(mSearchPreAllFolder)
                val rootFolderId = mBreadcrumb.firstFolder?.id
                if (rootFolderId == SDCARD_PATH || rootFolderId == DOWNLOAD_PATH) {
                    mBreadcrumb.visibility = View.VISIBLE
                } else {
                    mBreadcrumb.visibility = View.GONE
                }
            } else {
                resetFolder(LATELY_PATH)
                mBreadcrumb.visibility = View.GONE
            }
            mSearchPreAllFolder = null
            mSearchText = null
        }
    }

    /**
     * 低版本搜索当前目录内容
     */
    private fun searchCurrentFolder(searchText: String) {
        mTaskJob?.cancel()
        val files = mCurrentFolderFiles
        if (files.isNullOrEmpty() || searchText.isEmpty()) {
            mTaskJob = null
            mAdapter.setList(mCurrentFolderFiles)
            return
        }

        mTaskJob = ThreadUtils.execute({
            val searchFiles = mutableListOf<File>()
            val searchStr = searchText.lowercase()
            for (file in files) {
                val name = file.name.lowercase()
                if (name.isEmpty()) {
                    continue
                }

                if (name.contains(searchStr)) {
                    searchFiles.add(file)
                }
            }

            searchFiles
        }) { updateAdapterData(it) }
    }

    /**
     * 判断文件是否选中，如果选中，则返回选中文件在已选文件中的下标，未选中则返回[RecyclerView.NO_POSITION]
     */
    internal fun isFileChosen(file: File): Int {
        var existIndex: Int = RecyclerView.NO_POSITION
        for (index in mChosenFileList.indices) {
            val chosenFile = mChosenFileList[index]
            if (file.path == chosenFile.path) {
                existIndex = index
                break
            }
        }

        return existIndex
    }

    override fun onBackPressed() {
        val rootFolderId = mBreadcrumb.firstFolder?.id
        if (mSearchMode || rootFolderId == SEARCH_PATH) {
            clickExitSearchMode()
            return
        }

        val back = mBreadcrumb.back()
        if (back == null) {
            super.onBackPressed()
        }
    }

    override fun onDestroy() {
        super.onDestroy()
        ThreadUtils.cancel()
    }

    /**
     * 重置根目录
     */
    private fun resetFolder(path: String) {
        mBreadcrumb.reset()
        mRootPath = path
        when (path) {
            SDCARD_PATH -> {
                mBreadcrumb.visibility = View.VISIBLE
                mBreadcrumb.addFolderSpan(Folder(SDCARD_PATH, FilePicker.stringRes.rootFolder))
            }

            IMAGE_PATH -> {
                mBreadcrumb.visibility = View.GONE
                mBreadcrumb.addFolderSpan(Folder(IMAGE_PATH, FilePicker.stringRes.image))
            }

            VIDEO_PATH -> {
                mBreadcrumb.visibility = View.GONE
                mBreadcrumb.addFolderSpan(Folder(VIDEO_PATH, FilePicker.stringRes.video))
            }

            AUDIO_PATH -> {
                mBreadcrumb.visibility = View.GONE
                mBreadcrumb.addFolderSpan(Folder(AUDIO_PATH, FilePicker.stringRes.audio))
            }

            DOWNLOAD_PATH -> {
                mBreadcrumb.visibility = View.VISIBLE
                mBreadcrumb.addFolderSpan(Folder(DOWNLOAD_PATH, FilePicker.stringRes.download))
            }

            DOCUMENT_PATH -> {
                mBreadcrumb.visibility = View.GONE
                mBreadcrumb.addFolderSpan(Folder(DOCUMENT_PATH, FilePicker.stringRes.document))
            }

            LATELY_PATH -> {
                mBreadcrumb.visibility = View.GONE
                mBreadcrumb.addFolderSpan(Folder(LATELY_PATH, FilePicker.stringRes.lately))
            }

            ZIP_PATH -> {
                mBreadcrumb.visibility = View.GONE
                mBreadcrumb.addFolderSpan(Folder(ZIP_PATH, FilePicker.stringRes.zip))
            }

            SEARCH_PATH -> {
                mBreadcrumb.visibility = View.VISIBLE
                mBreadcrumb.addFolderSpan(Folder(SEARCH_PATH, FilePicker.stringRes.searchContent), false)
            }
        }
    }

    /**
     * 更新标题内容
     */
    private fun updateTitle() {
        if (!mShowMenu || (mChosenFileList.size > 0 && maxChosenCount > 1)
            || (maxChosenCount <= 0 && mClickFileChosen)) {
            mTvTitle.text =
                String.format(FilePicker.stringRes.fileChosenCountFormat, mChosenFileList.size, maxChosenCount)
            mIvMore.setImageResource(R.drawable.fp_check_24)
            return
        }

        mIvMore.setImageResource(R.drawable.fp_more_vert_24)
        val folder = mBreadcrumb.currentFolder
        mTvTitle.text = folder?.name
    }

    /**
     * 目录发生变更，进入下层目录或返回上层目录
     */
    private fun onFolderChange(folder: Folder) {
        updateTitle()
        when (folder.id) {
            SDCARD_PATH -> {
                @Suppress("DEPRECATION")
                val directory = Environment.getExternalStorageDirectory()
                setNewFolder(directory, 200, folder.extraData as? Int ?: 0)
            }

            IMAGE_PATH -> {
                queryImage(folder.extraData as? Int ?: 0)
            }

            VIDEO_PATH -> {
                queryVideo(folder.extraData as? Int ?: 0)
            }

            AUDIO_PATH -> {
                queryAudio(folder.extraData as? Int ?: 0)
            }

            DOWNLOAD_PATH -> {
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
                    queryDownloads(folder.extraData as? Int ?: 0)
                }
            }

            DOCUMENT_PATH -> {
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
                    queryDocument(folder.extraData as? Int ?: 0)
                }
            }

            LATELY_PATH -> {
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
                    queryLately(folder.extraData as? Int ?: 0)
                }
            }

            ZIP_PATH -> {
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
                    queryZip(folder.extraData as? Int ?: 0)
                }
            }

            SEARCH_PATH -> {
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
                    mSearchText?.let {
                        searchFile(it)
                    }
                }
            }

            else -> {
                setNewFolder(folder.id?.let { File(it) }, position = folder.extraData as? Int ?: 0)
            }
        }
    }

    /**
     * 更新目录下的数据
     */
    private fun setNewFolder(folder: File?, delayTime: Long = 0, position: Int? = null) {
        mTaskJob?.cancel()
        if (folder == null) {
            mTaskJob = null
            mAdapter.setList(null)
            return
        }

        mTaskJob = ThreadUtils.execute({
            val data = folder.listFiles { file ->
                return@listFiles isValidFile(file)
            }?.sortedWith { o1, o2 -> sortFile(o1, o2) }

            if (delayTime > 0) {
                delay(delayTime)
            }
            data
        }) { updateAdapterData(it, position) }
    }

    private fun isValidFile(file: File): Boolean {
        val name = file.name
        if (!mShowHideFile && name.startsWith(".")) {
            return false
        }

        if (!file.isDirectory) {
            if (maxFileSize > 0 && file.length() >= maxFileSize) {
                return false
            }

            var typeValid: Boolean? = null
            if (!mFileExtensionList.isNullOrEmpty()) {
                mFileExtensionList?.let {
                    typeValid = false
                    for (extension in it) {
                        if (name.endsWith(".$extension")) {
                            typeValid = true
                            return@let
                        }
                    }
                }
            }

            if (typeValid == null || typeValid == false) {
                if (!mFileMimeList.isNullOrEmpty()) {
                    val fileMime = MimeUtils.getFileMimeFromUrl(name)
                    mFileMimeList?.let {
                        typeValid = false
                        for (mime in it) {
                            if (mime == fileMime) {
                                typeValid = true
                                return@let
                            }
                        }
                    }
                }
            }

            if (typeValid == false) {
                return false
            }

            // 排除文件
            typeValid = null
            if (!mExcludeFileExtensionList.isNullOrEmpty()) {
                mExcludeFileExtensionList?.let {
                    typeValid = true
                    for (extension in it) {
                        if (name.endsWith(".$extension")) {
                            typeValid = false
                            return@let
                        }
                    }
                }
            }

            if (typeValid == null || typeValid == true) {
                if (!mExcludeFileMimeList.isNullOrEmpty()) {
                    val fileMime = MimeUtils.getFileMimeFromUrl(name)
                    mExcludeFileMimeList?.let {
                        typeValid = true
                        for (mime in it) {
                            if (mime == fileMime) {
                                typeValid = false
                                return@let
                            }
                        }
                    }
                }
            }

            if (typeValid == false) {
                return false
            }
        }

        return true
    }

    /**
     * 更新adapter数据
     * @param position 指定列表滑动到的位置
     */
    private fun updateAdapterData(list: List<File>?, position: Int? = 0) {
        if (mAdapter.isGridLayout) {
            if (list.isNullOrEmpty()) {
                mAdapter.setList(list)
            } else {
                var folderCount = 0
                for (file in list) {
                    if (file.isDirectory) {
                        folderCount++
                    } else {
                        break
                    }
                }

                if (folderCount > 0 && folderCount < list.size && folderCount % 2 != 0) {
                    val newList = ArrayList(list)
                    newList.add(folderCount, File(PLACE_HOLDER_FOlDER))
                    mAdapter.setList(newList)
                } else {
                    mAdapter.setList(list)
                }
            }
        } else {
            mAdapter.setList(list)
        }

        if (position == null || list == null || position < 0 || position >= list.size) {
            return
        }
        mLayoutManager.scrollToPositionWithOffset(position, 0)
    }

    /**
     * 对两个文件进行排序
     */
    private fun sortFile(file1: File, file2: File): Int {
        if (!file1.isFile && !file1.isDirectory) {
            return 1
        }

        if (!file2.isFile && !file2.isDirectory) {
            return -1
        }

        if (file1.isFile && file2.isDirectory) {
            return 1
        }

        if (file2.isFile && file1.isDirectory) {
            return -1
        }

        if (mSortType == SORT_TYPE_NAME_AZ || mSortType == SORT_TYPE_NAME_ZA) {
            val leftName: String
            val rightName: String
            if (mSortType == SORT_TYPE_NAME_AZ) {
                leftName = file1.name
                rightName = file2.name
            } else {
                leftName = file2.name
                rightName = file1.name
            }

            val c: Int = leftName.lowercase().compareTo(rightName.lowercase())
            return c.compareTo(0)
        }

        val leftTime: Long
        val rightTime: Long
        if (mSortType == SORT_TYPE_TIME_ASC) {
            leftTime = file1.lastModified()
            rightTime = file2.lastModified()
        } else {
            leftTime = file2.lastModified()
            rightTime = file1.lastModified()
        }

        val c: Int = leftTime.compareTo(rightTime)
        return c.compareTo(0)
    }

    /**
     * 查询文件
     * @param uri 映射至提供程序中名为 table_name 的表
     * @param sortByFolder 查询结束是否还需要按照目录文件进行排序
     */
    @Suppress("DEPRECATION")
    private fun queryFiles(uri: Uri,
                           whereSql: String? = null,
                           sortByFolder: Boolean = false,
                           position: Int = 0,
                           queryFolder: Boolean = false) {
        mTaskJob?.cancel()
        mTaskJob = ThreadUtils.execute({
            val projection =
                arrayOf(MediaStore.MediaColumns.DATA)
            var selection = "${MediaStore.MediaColumns.DATA} != ?"
            if (!mShowHideFile) {
                selection += " and ${MediaStore.MediaColumns.DISPLAY_NAME} not like '.%'"
            }

            if (whereSql != null) {
                selection += " and $whereSql"
            }

            var arg = getFileTypeWhereSql()
            if (maxFileSize > 0) {
                arg = if (arg == null) "${MediaStore.MediaColumns.SIZE} <= $maxFileSize" else
                    "$arg and ${MediaStore.MediaColumns.SIZE} <= $maxFileSize"
            }
            if (arg != null && queryFolder) {
                arg = "(${MediaStore.Images.Media.MIME_TYPE} IS NULL or ($arg))"
            }
            if (arg != null) {
                selection += " and $arg"
            }

            val selectionArgs = arrayOf("")
            val sortOrder = getSortWhereSql()

            val query = application.contentResolver.query(
                uri,
                projection,
                selection,
                selectionArgs,
                sortOrder
            )
            query?.use { cursor ->
                try {
                    val dataColumn = cursor.getColumnIndexOrThrow(MediaStore.MediaColumns.DATA)
                    val fileList = mutableListOf<File>()
                    while (cursor.moveToNext()) {
                        val data = cursor.getString(dataColumn)
                        fileList += File(data)
                    }

                    var data: List<File> = fileList
                    if (sortByFolder) {
                        data = data.sortedWith { o1, o2 -> sortFile(o1, o2) }
                    }

                    // 等抽屉关闭再刷新
                    delay(200)
                    data
                } catch (e: Exception) {
                    if (BuildConfig.DEBUG) {
                        e.printStackTrace()
                    }
                    null
                }
            }
        }) { updateAdapterData(it, position) }
    }

    /**
     * 获取要查找的文件sql条件语句
     */
    private fun getFileTypeWhereSql(): String? {
        var includeSql: String? = null
        mFileMimeWhereSql?.let {
            includeSql = "${MediaStore.Images.Media.MIME_TYPE} in ($it)"
        }

        if (!mFileExtensionList.isNullOrEmpty()) {
            mFileExtensionList?.let {
                val builder = StringBuilder("(")
                for (index in it.indices) {
                    val extension = it[index]
                    if (index == 0) {
                        builder.append("${MediaStore.Images.Media.DISPLAY_NAME} like '%.${extension}'")
                    } else {
                        builder.append(" or ${MediaStore.Images.Media.DISPLAY_NAME} like '%.${extension}'")
                    }
                }
                builder.append(")")
                includeSql = if (includeSql == null) {
                    builder.toString()
                } else {
                    "($includeSql or $builder)"
                }
            }
        }

        var excludeSql: String? = null
        mExcludeFileMimeWhereSql?.let {
            excludeSql = "${MediaStore.Images.Media.MIME_TYPE} not in ($it)"
        }

        if (!mExcludeFileExtensionList.isNullOrEmpty()) {
            mExcludeFileExtensionList?.let {
                val builder = StringBuilder("(")
                for (index in it.indices) {
                    val extension = it[index]
                    if (index == 0) {
                        builder.append("${MediaStore.Images.Media.DISPLAY_NAME} not like '%.${extension}'")
                    } else {
                        builder.append(" or ${MediaStore.Images.Media.DISPLAY_NAME} not like '%.${extension}'")
                    }
                }
                builder.append(")")
                excludeSql = if (excludeSql == null) {
                    builder.toString()
                } else {
                    "($excludeSql and $builder)"
                }
            }
        }

        if (includeSql == null) {
            return excludeSql
        }

        if (excludeSql == null) {
            return includeSql
        }

        return "($includeSql and $excludeSql)"
    }

    /**
     * 获取排序sql条件语句
     */
    private fun getSortWhereSql(): String {
        return if (mSortType == SORT_TYPE_NAME_AZ || mSortType == SORT_TYPE_NAME_ZA) {
            "${MediaStore.MediaColumns.DISPLAY_NAME} ${if (mSortType == SORT_TYPE_NAME_AZ) "ASC" else "DESC"}"
        } else {
            "${MediaStore.MediaColumns.DATE_MODIFIED} ${if (mSortType == SORT_TYPE_TIME_ASC) "ASC" else "DESC"}"
        }
    }

    /**
     * 查询所有图片
     */
    private fun queryImage(position: Int = 0) {
        val collection =
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
                MediaStore.Images.Media.getContentUri(MediaStore.VOLUME_EXTERNAL)
            } else {
                MediaStore.Images.Media.EXTERNAL_CONTENT_URI
            }
        queryFiles(collection, position = position)
    }

    /**
     * 查询所有视频
     */
    private fun queryVideo(position: Int = 0) {
        val collection =
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
                MediaStore.Video.Media.getContentUri(MediaStore.VOLUME_EXTERNAL)
            } else {
                MediaStore.Video.Media.EXTERNAL_CONTENT_URI
            }
        queryFiles(collection, position = position)
    }

    /**
     * 查询所有音频
     */
    private fun queryAudio(position: Int = 0) {
        val collection =
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
                MediaStore.Audio.Media.getContentUri(MediaStore.VOLUME_EXTERNAL)
            } else {
                MediaStore.Audio.Media.EXTERNAL_CONTENT_URI
            }
        queryFiles(collection, position = position)
    }

    /**
     * 查询所有下载内容
     */
    @RequiresApi(Build.VERSION_CODES.Q)
    private fun queryDownloads(position: Int = 0) {
        val collection = MediaStore.Downloads.getContentUri(MediaStore.VOLUME_EXTERNAL)
        queryFiles(collection, sortByFolder = true, position = position)
    }

    /**
     * 查询文档数据
     */
    @RequiresApi(Build.VERSION_CODES.Q)
    private fun queryDocument(position: Int = 0) {
        val collection = MediaStore.Files.getContentUri(MediaStore.VOLUME_EXTERNAL)
        val selection =
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
                "(${MediaStore.Files.FileColumns.MEDIA_TYPE} = ${MediaStore.Files.FileColumns.MEDIA_TYPE_DOCUMENT})"
            } else {
                "(${MediaStore.Files.FileColumns.DISPLAY_NAME} like '%.doc' " +
                    "or ${MediaStore.Files.FileColumns.DISPLAY_NAME} like '%.docx'" +
                    "or ${MediaStore.Files.FileColumns.DISPLAY_NAME} like '%.ppt'" +
                    "or ${MediaStore.Files.FileColumns.DISPLAY_NAME} like '%.pptx'" +
                    "or ${MediaStore.Files.FileColumns.DISPLAY_NAME} like '%.xls'" +
                    "or ${MediaStore.Files.FileColumns.DISPLAY_NAME} like '%.xlsx'" +
                    "or ${MediaStore.Files.FileColumns.DISPLAY_NAME} like '%.pdf'" +
                    "or ${MediaStore.Files.FileColumns.DISPLAY_NAME} like '%.txt'" +
                    "or ${MediaStore.Files.FileColumns.DISPLAY_NAME} like '%.xml'" +
                    "or ${MediaStore.Files.FileColumns.DISPLAY_NAME} like '%.html'" +
                    "or ${MediaStore.Files.FileColumns.DISPLAY_NAME} like '%.json')"
            }

        queryFiles(collection, selection, position = position)
    }

    /**
     * 查询最近7天进行更新过/创建的文件
     */
    @RequiresApi(Build.VERSION_CODES.Q)
    private fun queryLately(position: Int = 0) {
        val collection = MediaStore.Files.getContentUri(MediaStore.VOLUME_EXTERNAL)
        // 数据库存储的时间单位是秒
        val now = Date().time / 1000
        // 7天之前
        val pre = now - 24 * 60 * 60 * 7L
        val selection =
            "(${MediaStore.Files.FileColumns.DATE_MODIFIED} >= '$pre' " +
                "and ${MediaStore.Files.FileColumns.DATE_MODIFIED} <= '$now' " +
                // 如果是文件夹，则MIME为null
                "and ${MediaStore.Files.FileColumns.MIME_TYPE} !='')"
        queryFiles(collection, selection, position = position)
    }

    /**
     * 查询压缩包
     */
    @RequiresApi(Build.VERSION_CODES.Q)
    private fun queryZip(position: Int = 0) {
        val collection = MediaStore.Files.getContentUri(MediaStore.VOLUME_EXTERNAL)
        val selection = "(" +
            "${MediaStore.Files.FileColumns.DISPLAY_NAME} like '%.zip' " +
            "or ${MediaStore.Files.FileColumns.DISPLAY_NAME} like '%.rar'" +
            "or ${MediaStore.Files.FileColumns.DISPLAY_NAME} like '%.7z'" +
            "or ${MediaStore.Files.FileColumns.DISPLAY_NAME} like '%.tar'" +
            "or ${MediaStore.Files.FileColumns.DISPLAY_NAME} like '%.tgr.gz'" +
            "or ${MediaStore.Files.FileColumns.DISPLAY_NAME} like '%.tar.bz2'" +
            "or ${MediaStore.Files.FileColumns.DISPLAY_NAME} like '%.tar.xz'" +
            ")"

        queryFiles(collection, selection, position = position)
    }

    /**
     * 搜索文件
     */
    @RequiresApi(Build.VERSION_CODES.Q)
    private fun searchFile(str: String, queryFolder: Boolean = false) {
        if (str.isEmpty()) {
            mTaskJob?.cancel()
            mTaskJob = null
            mAdapter.setList(null)
            return
        }

        val collection = MediaStore.Files.getContentUri(MediaStore.VOLUME_EXTERNAL)
        val selection = "${MediaStore.Files.FileColumns.DISPLAY_NAME} like '%$str%'"
        queryFiles(collection, selection, true, queryFolder = queryFolder)
    }

    @SuppressLint("InflateParams")
    private fun showMenu() {
        val contentView = layoutInflater.inflate(R.layout.fp_pop_menu, null)
        val pop =
            PopupWindow(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT)
        pop.contentView = contentView
        pop.isOutsideTouchable = true
        pop.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT))
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
            pop.elevation = 10f
        }
        pop.isFocusable = true

        val tvSortType = contentView.findViewById<TextView>(R.id.tv_sort_type)
        tvSortType.text = FilePicker.stringRes.sortType

        val tvShowHideFile = contentView.findViewById<TextView>(R.id.tv_show_hide_file)
        tvShowHideFile.text =
            if (mShowHideFile) FilePicker.stringRes.notShowHideFile else FilePicker.stringRes.showHideFile
        tvShowHideFile.setOnClickListener {
            pop.dismiss()
            mShowHideFile = !mShowHideFile
            mBreadcrumb.currentFolder?.let {
                onFolderChange(it)
            }
        }

        contentView.findViewById<TextView>(R.id.tv_sort_type).setOnClickListener {
            pop.dismiss()
            showSortTypePop()
        }

        pop.showAsDropDown(mIvMore)
    }

    @SuppressLint("InflateParams")
    private fun showSortTypePop() {
        val contentView = layoutInflater.inflate(R.layout.fp_pop_sort_type, null)
        val dialog = Dialog(this, R.style.fp_TransparentWindowTheme)
        dialog.setCanceledOnTouchOutside(true)
        // requestWindowFeature必须在setContentView之前调用
        dialog.requestWindowFeature(Window.FEATURE_NO_TITLE)
        dialog.setContentView(contentView)
        val window = dialog.window
        if (window != null) {
            window.decorView.setPadding(0, 0, 0, 0)
            val wl = window.attributes
            wl.width = ViewGroup.LayoutParams.MATCH_PARENT
            wl.height = ViewGroup.LayoutParams.WRAP_CONTENT
            wl.windowAnimations = R.style.fp_dialog_animation_from_bottom
            window.setGravity(Gravity.BOTTOM)
            dialog.onWindowAttributesChanged(wl)
        }

        val tvSortType = contentView.findViewById<TextView>(R.id.tv_sort_type)
        tvSortType.text = FilePicker.stringRes.sortType

        val mTvSortAz = contentView.findViewById<TextView>(R.id.tv_sort_az)
        val mIvSortAz = contentView.findViewById<AppCompatImageView>(R.id.iv_sort_az)
        val mLlSortAz = contentView.findViewById<LinearLayout>(R.id.ll_sort_az)
        val mTvSortZa = contentView.findViewById<TextView>(R.id.tv_sort_za)
        val mIvSortZa = contentView.findViewById<AppCompatImageView>(R.id.iv_sort_za)
        val mLlSortZa = contentView.findViewById<LinearLayout>(R.id.ll_sort_za)
        val mTvTimeDesc = contentView.findViewById<TextView>(R.id.tv_time_desc)
        val mIvTimeDesc = contentView.findViewById<AppCompatImageView>(R.id.iv_time_desc)
        val mLlTimeDesc = contentView.findViewById<LinearLayout>(R.id.ll_time_desc)
        val mTvTimeAsc = contentView.findViewById<TextView>(R.id.tv_time_asc)
        val mIvTimeAsc = contentView.findViewById<AppCompatImageView>(R.id.iv_time_asc)
        val mLlTimeAsc = contentView.findViewById<LinearLayout>(R.id.ll_time_asc)

        mTvSortAz.text = FilePicker.stringRes.sortFileNameAz
        mTvSortZa.text = FilePicker.stringRes.sortFileNameZa
        mTvTimeDesc.text = FilePicker.stringRes.sortFileTimeDesc
        mTvTimeAsc.text = FilePicker.stringRes.sortFileTimeAsc

        when (mSortType) {
            SORT_TYPE_NAME_AZ -> {
                mIvSortAz.visibility = View.VISIBLE
                mTvSortAz.setTextColor(ContextCompat.getColor(this, R.color.fp_text_color_sky_blue))
            }

            SORT_TYPE_NAME_ZA -> {
                mIvSortZa.visibility = View.VISIBLE
                mTvSortZa.setTextColor(ContextCompat.getColor(this, R.color.fp_text_color_sky_blue))
            }

            SORT_TYPE_TIME_DESC -> {
                mIvTimeDesc.visibility = View.VISIBLE
                mTvTimeDesc.setTextColor(ContextCompat.getColor(this, R.color.fp_text_color_sky_blue))
            }

            SORT_TYPE_TIME_ASC -> {
                mIvTimeAsc.visibility = View.VISIBLE
                mTvTimeAsc.setTextColor(ContextCompat.getColor(this, R.color.fp_text_color_sky_blue))
            }
        }

        mLlSortAz.setOnClickListener {
            dialog.dismiss()
            if (mSortType == SORT_TYPE_NAME_AZ) {
                return@setOnClickListener
            }

            mSortType = SORT_TYPE_NAME_AZ
            mBreadcrumb.currentFolder?.let {
                onFolderChange(it)
            }
        }

        mLlSortZa.setOnClickListener {
            dialog.dismiss()
            if (mSortType == SORT_TYPE_NAME_ZA) {
                return@setOnClickListener
            }

            mSortType = SORT_TYPE_NAME_ZA
            mBreadcrumb.currentFolder?.let {
                onFolderChange(it)
            }
        }

        mLlTimeDesc.setOnClickListener {
            dialog.dismiss()
            if (mSortType == SORT_TYPE_TIME_DESC) {
                return@setOnClickListener
            }

            mSortType = SORT_TYPE_TIME_DESC
            mBreadcrumb.currentFolder?.let {
                onFolderChange(it)
            }
        }

        mLlTimeAsc.setOnClickListener {
            dialog.dismiss()
            if (mSortType == SORT_TYPE_TIME_ASC) {
                return@setOnClickListener
            }

            mSortType = SORT_TYPE_TIME_ASC
            mBreadcrumb.currentFolder?.let {
                onFolderChange(it)
            }
        }

        dialog.show()
    }

    @SuppressLint("InflateParams", "NotifyDataSetChanged")
    override fun onConfigurationChanged(newConfig: Configuration) {
        super.onConfigurationChanged(newConfig)
        val isNight =
            newConfig.uiMode and Configuration.UI_MODE_NIGHT_MASK == Configuration.UI_MODE_NIGHT_YES
        if (isNight != mDarkTheme) {
            mDarkTheme = isNight
            setNewAdapter()
        }
    }

    /**
     * 更改adapter布局
     */
    private fun updateAdapterLayout(isGridLayout: Boolean) {
        if (isGridLayout && mLayoutManager is GridLayoutManager) {
            return
        }

        if (!isGridLayout && mLayoutManager !is GridLayoutManager) {
            return
        }

        val position = mLayoutManager.findFirstVisibleItemPosition()
        mLayoutManager = if (isGridLayout) {
            mIvChangeLayout.setImageResource(R.drawable.fp_view_list_24)
            val padding = (resources.displayMetrics.density * 20).toInt()
            mRecyclerView.setPadding(padding, 0, padding, 0)
            mAdapter.isGridLayout = true
            GridLayoutManager(this, mSpanCount).apply {
                spanSizeLookup = object : GridLayoutManager.SpanSizeLookup() {
                    override fun getSpanSize(position: Int): Int {
                        val data = mAdapter.data
                        if (position < 0 || position >= data.size) {
                            return 1
                        }

                        val file = data[position]
                        return if (file.path == PLACE_HOLDER_FOlDER) {
                            mSpanCount - position % mSpanCount
                        } else {
                            1
                        }
                    }
                }
            }
        } else {
            mIvChangeLayout.setImageResource(R.drawable.fp_view_module_24)
            mRecyclerView.setPadding(0, 0, 0, 0)
            mAdapter.isGridLayout = false
            LinearLayoutManager(this)
        }
        mRecyclerView.layoutManager = mLayoutManager

        val list = mAdapter.data
        if (mAdapter.isGridLayout) {
            var folderCount = 0
            for (file in list) {
                if (file.isDirectory) {
                    folderCount++
                } else {
                    break
                }
            }

            if (folderCount > 0 && folderCount < list.size && folderCount % 2 != 0) {
                val newList = ArrayList(list)
                newList.add(folderCount, File(PLACE_HOLDER_FOlDER))
                mAdapter.setList(newList)
            }
        } else {
            var placeHolderFolderIndex = -1
            for (index in list.indices) {
                val file = list[index]
                if (file.isDirectory || PLACE_HOLDER_FOlDER == file.path) {
                    if (PLACE_HOLDER_FOlDER == file.path) {
                        placeHolderFolderIndex = index
                        break
                    }
                } else {
                    break
                }
            }
            if (placeHolderFolderIndex != -1) {
                mAdapter.removeAt(placeHolderFolderIndex)
            }
        }

        mRecyclerView.adapter = mAdapter
        if (position != RecyclerView.NO_POSITION && position > 0 && position < mAdapter.data.size) {
            mLayoutManager.scrollToPositionWithOffset(position, 0)
        }
    }

    companion object {
        private const val SDCARD_PATH = "1"
        private const val IMAGE_PATH = "2"
        private const val VIDEO_PATH = "3"
        private const val AUDIO_PATH = "4"
        private const val DOWNLOAD_PATH = "5"
        private const val DOCUMENT_PATH = "6"
        private const val LATELY_PATH = "7"
        private const val ZIP_PATH = "8"
        private const val SEARCH_PATH = "9"

        /**
         * 占位文件夹
         */
        internal const val PLACE_HOLDER_FOlDER = "/placeHolderFolder"

        /**
         * 按照名称从A~Z排序
         */
        private const val SORT_TYPE_NAME_AZ = 0

        /**
         * 按照名称从Z~A排序
         */
        private const val SORT_TYPE_NAME_ZA = 1

        /**
         * 按照最后修改时间由远到近排序
         */
        private const val SORT_TYPE_TIME_ASC = 2

        /**
         * 按照最后修改时间由近到远排序
         */
        private const val SORT_TYPE_TIME_DESC = 3

        /**
         * 最多可选数量
         */
        const val MAX_CHOOSE_COUNT = "maxChooseCount"

        /**
         * 选择的文件扩展
         */
        const val CHOSEN_FILE_EXTENSION = "chosenFileExtension"

        /**
         * 排除的文件扩展
         */
        const val EXCLUDE_FILE_EXTENSION = "excludeFileExtension"

        /**
         * 选择的文件MIME
         */
        const val CHOSEN_FILE_MIME = "chosenFileMime"

        /**
         * 排除的文件MIME
         */
        const val EXCLUDE_FILE_MIME = "excludeFileMime"

        /**
         * 默认打开的路径
         */
        const val DEFAULT_OPEN_PATH = "defaultOpenPath"

        /**
         * 已选择文件列表
         */
        const val CHOSEN_DATA_LIST = "chosenDataList"

        /**
         * 如果以网格模式展示，展示成几列
         */
        const val SPAN_COUNT = "spanCount"

        /**
         * 首选展示布局
         */
        const val PREFERRED_LAYOUT = "preferredLayout"

        /**
         * 文件最大大小，超出则不可选择
         */
        const val MAX_FILE_SIZE = "maxFileSize"

        /**
         * 是否显示菜单按钮
         */
        const val SHOW_MENU = "showMenu"
    }
}
